import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

// Klassen WordList innehåller en ordlista och en datastruktur som håller
// reda på använda ord.

class WordList {
	static private HashMap<Word, HashSet<Word>> list; // ordlista
	static private HashMap<Word, Word> used; // databas med använda ord
	static int wordLength;
	static int size; // antal ord i ordlistan

	// Read läser in en ordlista från strömmen input. Alla ord ska ha
	// wordLength bokstäver.
	static public void Read(int wordLength_, BufferedReader input)
			throws IOException {
		wordLength = wordLength_;
		size = 0;
		list = new HashMap<Word, HashSet<Word>>();
		while (true) {
			String s = input.readLine();
			if (s.equals("#"))
				break;
			if (s.length() != wordLength)
				System.out.println("Rad " + size + " i filen innehåller inte "
						+ wordLength + " tecken.");
			list.put(new Word(s), null);
			size++;
		}
		used = new HashMap<Word, Word>(size);
		findNeighbours();
	}

	static public Iterator<Word> iterator() {
		return list.keySet().iterator();
	}

	// Contains slår upp w i ordlistan och returnerar ordet om det finns med.
	// Annars returneras null.
	static public boolean Contains(Word w) {
		if (list.containsKey(w))
			return true;
		else
			return false;
	}

	static public HashSet<Word> getChildren(Word w) {
		/*
		 * HashSet<Word> ll = list.get(w); LinkedList<Word> retL = new
		 * LinkedList<Word>(); for(Word word : ll){ if(!used.contains(word)){
		 * used.add(word); retL.add(word); } } return retL;
		 */
		return list.get(w);
	}

	// MarkAsUsedIfUnused kollar om w är använt tidigare och returneras i så
	// fall false. Annars markeras w som använt och true returneras.
	static public boolean MarkAsUsedIfUnused(Word w, Word parent) {
		if (used.containsKey(w))
			return false;
		parent = (parent == null) ? null : new Word(parent);
		w = (w == null) ? null : new Word(w);
		used.put(w, parent);
		return true;
	}

	static public Word getParent(Word w) {
		return used.get(w);
	}

	// EraseUsed gör så att inga ord anses använda längre.
	static public void EraseUsed() {
		used.clear();
	}

	static private void findNeighbours() {
		Iterator<Word> it = list.keySet().iterator();
		while (it.hasNext()) {
			Word key = it.next();
			list.put(key, getNeighbours(key));
		}
	}

	static private HashSet<Word> getNeighbours(Word w) {
		HashSet<Word> ll = new HashSet<Word>();
		for (int i = 0; i < 4; i++) {
			Word mutate = new Word(w);
			for (char c : LongestChain.alphabet) {
				mutate.data[i] = c;
				if (list.containsKey(mutate)) {
					ll.add(new Word(mutate));
				}
			}
		}
		return ll;
	}

}